package org.semanticflash.rdf.graph.source
{
	
	
	import com.bigflexlib.ds.container.zet.IOSet;
	import com.bigflexlib.ds.container.zet.IOWSet;
	import com.bigflexlib.ds.container.zet.impl.owSet;
	
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.utils.Dictionary;
	
	import mx.rpc.events.ResultEvent;
	import mx.rpc.http.HTTPService;
	
	import org.semanticflash.rdf.io.RDFSetHandler;
	import org.semanticflash.rdf.io.rdfxml.RDFXMLParser;
	import org.semanticflash.rdf.io.rdfxml.RDFXMLParserUtil;
	import org.semanticflash.rdf.triple.IRDFTripleProvider;
	import org.semanticflash.rdf.values.IRI;



	/**
	 * 
	 * 
	 * 
	 * @author aldo.bucchi@gmail.com
	 * 
	 */
	public class RDFRemoteSource extends EventDispatcher implements IRDFTripleProvider
	{


		// states
		public static const INITIAL:String 	= "initial";
		public static const LOADED:String 	= "loaded";
		public static const LOADING:String 	= "loading";
		public static const ERROR:String 		= "error";




		private var _iri:IRI;
		public function get iri( ):IRI
		{
			return _iri;		
		}		
		



		
		private var _triples:IOWSet;
		/**
		 * 
		 * Triples that were extracted from this source
		 * 
		 * @return 
		 * 
		 */		
		public function get triples( ):IOSet
		{
			return _triples;					
		}


		
		
		private var _state:String = INITIAL;
		[Bindable("stateChanged")]
		public function get state( ):String
		{
			return _state;		
		}








		private var srv:HTTPService;


		private var firstTry:Boolean = true;



		public function RDFRemoteSource( iri:IRI )
		{
			
			_iri = iri;	
			
			_triples = owSet();


			srv = new HTTPService( );

			srv.headers = {
					Accept : "application/rdf+xml"
				};
				
			srv.resultFormat = "e4x";
			
			srv.url = composeTriplrURLForIRI( iri, "rdf" );

			srv.addEventListener( ResultEvent.RESULT, onResult );

		}
		
		
		
		
		
		public function load( ):void
		{
			if ( state == LOADING )
			{
				return;
			}
		
			srv.send( );		
			setState( LOADING );
		}
		
		
		
		public function unload( ):void
		{
			_triples.clear( );

		}
		
		
		

		
		
		private function onResult( event:ResultEvent ):void
		{
			
			
			var docXML:XML = event.result as XML;

			
			// is this rdf-xml??
			var isRDFXML:Boolean = RDFXMLParserUtil.isRDFXML( docXML );


			
			if ( ! isRDFXML )
			{
			
				if ( firstTry && (1==2) ) // try again, but this time use triplr
				{
				
					firstTry = false;
					srv.url = composeTriplrURLForIRI( iri );
					srv.send( );
					
					trace( "will try triplr" );
					
					return;
				}

				trace( "could not parse..." );
			
				return;
			
			}



			var h:RDFSetHandler = new RDFSetHandler( _triples );
			
			var parser:RDFXMLParser = new RDFXMLParser( docXML, h, iri.asURI.toString( ) );
			
			_triples.autoUpdateFlag.disable( );
			// we will run the parser to completion in one go
			parser.runner.run( );			
			_triples.autoUpdateFlag.enable( );


			setState( LOADED );
			
		}
		
		




		private function composeTriplrURLForIRI( iri:IRI, format:String = "rdf" ):String
		{
			// strip fragment
			iri = iri.noFragment;
			
			// strip scheme ( TODO )
			// var uri:URI = iri.asURI;
			return "http://triplr.org/" + format + "/" + iri.stringForm ;		
		}




		
		
		private function setState( state:String ):void
		{
		
			if ( _state == state )
			{
				return;
			}
			_state = state;
			
			dispatchEvent( new Event( "stateChanged" ) );
		
		}		
		
		
		
		
		
		////////////////////////////////////////////////////////////
		///////////////////////// factory //////////////////////////
		////////////////////////////////////////////////////////////
		
		
		private static var cache:Dictionary = new Dictionary( true );
		
		
		/**
		 * 
		 * Returns a remote source for <b>dereferencable</b> iris
		 * ( otherwise returns NULL )
		 * 
		 * @param iri
		 * @return 
		 * 
		 */		
		public static function forIRI( iri:IRI ):RDFRemoteSource
		{
			
			if ( ! iri.isDereferencable )
			{
				return null;
			}
			
			
			iri = iri.noFragment;
			
			if ( ! cache[ iri ] )
			{
				var r:RDFRemoteSource = new RDFRemoteSource( iri );
				cache[ iri ] = r;
				return r;			
			}
		
			return cache[ iri ] as RDFRemoteSource;
		
		
		}
		
		
		
		
	
		
		
	}
	
	
}




